package com.srwl.mytx.im;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.srwl.mytx.Constant;
import com.srwl.mytx.im.conversation.AdvertisementNotifyConversation;
import com.srwl.mytx.im.conversation.ContactNotifyConversation;
import com.srwl.mytx.domain.ConversationData;
import com.srwl.mytx.im.conversation.Conversation;
import com.srwl.mytx.domain.Message;
import com.srwl.mytx.dao.DBManager;
import com.srwl.mytx.greendao.ConversationDataDao;
import com.srwl.mytx.im.conversation.SystemNotifyConversation;
import com.srwl.mytx.im.conversation.TaskNotifyConversation;
import com.srwl.mytx.im.conversation.TransferAuthorityConversation;
import com.srwl.mytx.im.conversation.WithdrawNotifyConversation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

public class ConversationService implements MessageHandlerImpl.MessageStateChangeListener, ConversationListener {
    private static final String TAG = "ConversationService";
    private Context context;
    private List<Conversation> conversationList = new ArrayList<>();
    private List<SystemNotifyConversation> notifyConversationList = new ArrayList<>();
    private ConversationListener conversationListener;
    private ConversationDataDao conversationDao;
    private Conversation.MessageUnReadCountListener messageUnReadCountListener;
    private MessageHandlerImpl messageHandler;
    //临时会话：没保存进数据库的会话
    private Conversation tempConversation;
    private List<Message> sendFailMessageList = new ArrayList<>(); //保存那些发送失败的消息，定时检测网络 重新发送
    //发送中的消息集合，发送提交完成，可能发送失败，也可能发送成功
    //不管是发送成功还是失败，都从这个集合中删除
    //这个集合存在的意义是，当一条消息是否成功，是以后端返回的 发送消息回执 来判断是否发送成功
    // 所以需要在这儿保持一个 发送消息的集合，以便在发送成功后，根据消息id ,拿到完整消息，再分发到各个会话
    private List<Message> sendingMessageList = new ArrayList<>();


    public ConversationService(Context context, Conversation.MessageUnReadCountListener messageUnReadCountListener) {
        this.context = context;
        this.messageUnReadCountListener = messageUnReadCountListener;
        init();
    }

    /**
     * 读取数据库，获取所有的会话，会话中关联了 message
     */
    private void init() {
        messageHandler = new MessageHandlerImpl(context, this);
        conversationDao = DBManager.getInstance().getDaoSession().getConversationDataDao();
       // List<ConversationData> conversationDataList = conversationDao.loadAll();
        List<ConversationData> conversationDataList = conversationDao.queryBuilder().orderDesc(ConversationDataDao.Properties.Updated).list(); //按更新时间降序
        //根据position属性排序
        Collections.sort(conversationDataList);
       // sortByUpdated(conversationDataList);
        for (ConversationData data : conversationDataList) {
            if (data.getType() == Constant.CONVERSATION_TYPE_C2C) {
                Conversation c2cConversation = new Conversation(data, messageHandler, messageUnReadCountListener);
                c2cConversation.setConversationListener(this);
                conversationList.add(c2cConversation);
            } else {
                Conversation notifyConversation = getNotifyConversation(data);
                conversationList.add(notifyConversation);
            }
        }
        sendFailMessageList = messageHandler.loadSentFailOrSendingMessageList();

    }

    /**
     * 根据更新时间排序
     *
     * @param conversationDataList
     */
    private void sortByUpdated(List<ConversationData> conversationDataList) {
        for (int i = 0; i < conversationDataList.size(); i++) {
            ConversationData conversationData = conversationDataList.get(i);
            if (conversationData.getPosition() != ConversationData.DEFAULT_POSITION) {
                continue;//位置不等于默认位置，表示属于置顶项，置顶项不参与 会话基于更新时间的排序
            }
            Date updated1 = conversationData.getUpdated();
            for (int z = conversationDataList.size() - 1; z >= 0; z--) {
                if (i == z) {
                    break;
                }
                Date updated2 = conversationDataList.get(z).getUpdated();
                if (updated2 == null) {
                    continue;
                }
                if (updated1 == null || updated2.after(updated1)) {
                    conversationDataList.add(i, conversationDataList.remove(z));
                }

            }
        }
    }


    /**
     * im 链接成功
     * 登录成功 或者是 重连成功
     */
    public void onConnectSuccess() {
        Log.i(TAG, "onConnectSuccess: im链接成功, 当前消息发送失败集合的长度是 " + sendFailMessageList.size());
        try {
            for (int i = 0; i < sendFailMessageList.size(); i++) {
                Message message = sendFailMessageList.remove(i);
                Log.d(TAG, "onConnectSuccess: 消息重发" + message.getId() + "  当前消息发送失败集合的长度是 " + sendFailMessageList.size());
                messageHandler.sendMessage(message);
                i--;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 从聊天页面 获取会话
     *
     * @param conversationId
     * @return
     */
    public Conversation getC2cConversation(String conversationId) {
        return getC2cConversation(conversationId, false);
    }

    /**
     * 获取c2c会话，没有就创建新会话
     *
     * @param toUserId 聊天对象 id,也是会话id
     * @return
     */
    private synchronized Conversation getC2cConversation(String toUserId, boolean save) {
        for (Conversation conversation : conversationList) {
            if (conversation.getCId().equals(toUserId)) {
                conversation.setToUserId(toUserId);
                return conversation;
            }
        }
        //在会话列表中没有找到对应的会话，检查 是否存在符合要求的零时会话
        if (tempConversation != null && TextUtils.equals(tempConversation.getToUserId(), toUserId)) {
            //保存临时会话
            if (save) {
                saveConversation(tempConversation);
            }
            return tempConversation;
        }
        //如果以上都没符合，需要创建一个新会话，
        tempConversation = new Conversation(toUserId, Constant.CONVERSATION_TYPE_C2C, messageHandler, messageUnReadCountListener);
        tempConversation.setConversationListener(this);
        //保存临时会话
        if (save) {
            saveConversation(tempConversation);
        }
        return tempConversation;
    }

    /**
     * 获取已经存在的c2c会话
     *
     * @param toUserId
     * @return
     */
    public Conversation getExistC2cConversation(String toUserId) {
        for (Conversation conversation : conversationList) {
            if (conversation.getCId().equals(toUserId)) {
                conversation.setToUserId(toUserId);
                return conversation;
            }
        }
        if (tempConversation != null && TextUtils.equals(tempConversation.getToUserId(), toUserId)) {
            return tempConversation;
        }
        return null;
    }

    /**
     * 把会话 添加进会后列表
     * 包括存入数据库
     * 显示到会话列表
     */
    private void saveConversation(Conversation conversation) {
        conversationList.add(conversation);
        conversation.saveData();
        conversation.setTempConversation(false);
        if (conversationListener != null) {
            conversationListener.onConversationAdd(conversation);
        }
    }

    /**
     * 删除会话
     */
    public void deleteConversation(Conversation conversation) {
        conversation.deleteAllMessage();
        conversationList.remove(conversation);
        tempConversation = conversation;
        conversation.setTempConversation(true);
        conversation.deleteData();
        if (conversationListener != null) {
            conversationListener.onConversationRemove(conversation);
        }
    }

    /**
     * 根据联系人id 删除会话
     *
     * @param targetUserId
     */
    public void deleteConversation(String targetUserId) {

        Conversation c2cConversation = getExistC2cConversation(targetUserId);
        if (c2cConversation != null) {
            deleteConversation(c2cConversation);
        }

    }

    /**
     * 分发用户发给用户的消息
     *
     * @param message
     */
    public synchronized void distributeC2CMessage(Message message) {
        String fromId = message.getFromId();

        Conversation targetConversation = getC2cConversation(fromId, true);
        targetConversation.receivedMessage(message);
        //非消息已读回值，才更新 会话列表
        if (conversationListener != null && message.getSubType() != Constant.IM_TYPE_MESSAGE_READ_ACK) {
            conversationListener.onMessageChange(targetConversation);
        }


    }

    /**
     * 分发系统消息
     *
     * @param message
     */
    public void distributeNotifyMessage(Message message) {
        if (message == null) {
            return;
        }
        Integer messageType = message.getType();
        if (messageType == null) {
            Log.e(TAG, "distributeNotifyMessage: 消息没有分类，，，" + message.toString());
            return;
        }
        switch (messageType) {
            case Constant.NOTIFY_MESSAGE_SYSTEM:
                Conversation systemNotifyConversation = getNotifyConversation(Constant.CONVERSATION_TYPE_SYSTEM);
                systemNotifyConversation.receivedMessage(message);

                break;
            case Constant.NOTIFY_MESSAGE_CONTACT: {
                Conversation notifyConversation = getNotifyConversation(Constant.CONVERSATION_TYPE_CONTACT);
                notifyConversation.receivedMessage(message);
            }
            break;
            case Constant.NOTIFY_MESSAGE_ADVERTISEMENT:
                Conversation notifyConversation = getNotifyConversation(Constant.CONVERSATION_TYPE_ADVERTISEMENT);
                notifyConversation.receivedMessage(message);
                break;
            case Constant.NOTIFY_MESSAGE_TASK:
                Conversation taskNotifyConversation = getNotifyConversation(Constant.CONVERSATION_TYPE_TASK);
                taskNotifyConversation.receivedMessage(message);
                break;
            case Constant.PUSH_MESSAGE_APPLY_WITHDRAW:
                Conversation transferConversation = getNotifyConversation(Constant.CONVERSATION_TYPE_WITHDRAW);
                transferConversation.receivedMessage(message);
                break;
            case Constant.NOTIFY_MESSAGE_TRANSFER_AUTHORITY:
                Conversation transferAuthorityConversation = getNotifyConversation(Constant.CONVERSATION_TYPE_TRANSFER_AUTHORITY);
                transferAuthorityConversation.receivedMessage(message);
                break;

            default:
                Log.e(TAG, "distributeNotifyMessage: 有消息类型没处理" + message.toString());

        }
    }

    public SystemNotifyConversation getNotifyConversation(Integer conversationType) {
        ConversationData data = new ConversationData(conversationType + "", 0, conversationType);
        return getNotifyConversation(data);
    }


    /**
     * 根据会话类型，获取通知类型的会话
     *
     * @return
     */
    private SystemNotifyConversation getNotifyConversation(ConversationData data) {
        int conversationType = data.getType();
        for (SystemNotifyConversation conversation : notifyConversationList) {
            if (conversation.getType() == conversationType) {
                return conversation;
            }
        }
//        //判断临时会话 是否是需要的会话
//        if (tempConversation != null && conversationType == tempConversation.getType()) {
//            //保存临时会话
//            saveConversation(tempConversation);
//            return tempConversation;
//        }
        SystemNotifyConversation conversation = null;
        switch (conversationType) {
            case Constant.CONVERSATION_TYPE_CONTACT:
                conversation = new ContactNotifyConversation(context, data, messageHandler, messageUnReadCountListener);
                break;
            case Constant.CONVERSATION_TYPE_ADVERTISEMENT:
                conversation = new AdvertisementNotifyConversation(context,data, messageHandler, messageUnReadCountListener);
                break;
            case Constant.CONVERSATION_TYPE_TASK:
                conversation = new TaskNotifyConversation(context,data, messageHandler, messageUnReadCountListener);
                break;
            case Constant.CONVERSATION_TYPE_WITHDRAW:
                conversation = new WithdrawNotifyConversation(context,data, messageHandler, messageUnReadCountListener);
                break;
            case Constant.CONVERSATION_TYPE_TRANSFER_AUTHORITY:
                conversation = new TransferAuthorityConversation(context,data, messageHandler, messageUnReadCountListener);
                break;
            default:
                conversation = new SystemNotifyConversation(context, data, messageHandler, messageUnReadCountListener);
                break;
        }
        conversation.setConversationListener(this);
        // conversation.saveData(); 不能在这儿保存 data,因为现在又能有不需要显示到页面的数据交给通知会话处理
        notifyConversationList.add(conversation);

        return conversation;
    }


    public void setConversationListener(ConversationListener conversationListener) {
        this.conversationListener = conversationListener;

    }

    public void onMessageSendSuccess(String messageId) {
        Message message;
        message = removeInSendMessageList(messageId);
        if (message == null) {
            Log.e(TAG, "onMessageSendSuccess: 从消息发送队列中没有找到对应的消息  messageId：" + messageId);
            return;
        }
        //  message = removeInSendFailMessageList(messageId);

        //如果是消息已读回执,就不用往页面传递了,并且在数据库中删除
        if (message.getSubType() == Constant.IM_TYPE_MESSAGE_READ_ACK) {
            messageHandler.deleteMessage(messageId);
            return;
        }

        message.setSendState(Constant.IM_SEND_STATE_SUCCESS);
        onMessageSendStateChange(message);
        messageHandler.setMessageSendState(message);
    }

    public void onMessageSendFail(String messageId) {
        Message message = removeInSendMessageList(messageId);
        if (message == null) {
            Log.w(TAG, "onMessageSendFail: 从消息发送队列中没有找到对应的消息 messageId： " + messageId);
            return;
        }
        message.setSendState(Constant.IM_SEND_STATE_FAIL);
        //如果消息发送失败，添加进一个集合里面，网络恢复后，自动发送
        addInSendFailMessageList(message);
        //如果是消息已读回执,就不用往页面传递了,
        // 已读回值的消息在正常发送的情况下，是不存入数据库的,所以在这儿需要整体存入数据库，而不是更新消息状态
        if (message.getSubType() == Constant.IM_TYPE_MESSAGE_READ_ACK) {
            messageHandler.saveMessage(message);
            return;
        }
        onMessageSendStateChange(message);
        //更新消息在本地数据库中的状态为失败状态
        messageHandler.setMessageSendState(message);
    }

    @Override
    public void onMessageSendFail(Message message) {
        onMessageSendFail(message.getId());
    }

    @Override
    public void onMessageSend(Message message) {
        sendingMessageList.add(message);
        Log.d(TAG, "onMessageSend: 添加消息进消息发送集合 消息id: " + message.getId() + "   ,消息发送集合长度是：" + sendingMessageList.size());
    }

    public void onMessageSendSuccess(Message message) {

        removeInSendFailMessageList(message);
//如果是消息已读回执,就不用往页面传递了,并且在数据库中删除
        if (message.getSubType() == Constant.IM_TYPE_MESSAGE_READ_ACK) {
            messageHandler.deleteMessage(message.getId());
            return;
        }

        message.setSendState(Constant.IM_SEND_STATE_SUCCESS);
        onMessageSendStateChange(message);
        messageHandler.setMessageSendState(message);

    }

    private void onMessageSendStateChange(Message message) {

        Conversation targetConversation = getC2cConversation(message.getToId(), true);

        targetConversation.updateMessageSendState(message);
        if (conversationListener != null) {
            conversationListener.onMessageChange(targetConversation);
        }

    }

    /**
     * 保存失败的消息进 发送失败消息集合
     *
     * @param sendFailMessage 发送失败的消息
     */
    private void addInSendFailMessageList(Message sendFailMessage) {

        for (int i = 0; i < sendFailMessageList.size(); i++) {
            Message message = sendFailMessageList.get(i);
            if (TextUtils.equals(message.getId(), sendFailMessage.getId())) {
                Log.e(TAG, "addInSendFailMessageList: 出现重复添加的发送失败消息");
                return;
            }
        }
        sendFailMessageList.add(sendFailMessage);
        Log.d(TAG, "addInSendFailMessageList: 添加进消息发送   ***失败***  集合的消息id:" + sendFailMessage.getId() + "  当前消息发送 ***失败*** 集合的长度为：" + sendFailMessageList.size());
    }

    /**
     * 检查发送成功的消息是否在发送失败列表里面，如果在，删除它
     *
     * @param sendSuccessMessage
     */
    private void removeInSendFailMessageList(Message sendSuccessMessage) {

        removeInSendFailMessageList(sendSuccessMessage.getId());
    }

    private Message removeInSendFailMessageList(String messageId) {

        for (int i = 0; i < sendFailMessageList.size(); i++) {
            Message message = sendFailMessageList.get(i);
            if (TextUtils.equals(message.getId(), messageId)) {
                return sendFailMessageList.remove(i);

            }
        }

        return null;
    }

    private Message removeInSendMessageList(String messageId) {

        Message messageBack = null;
        for (int i = 0; i < sendingMessageList.size(); i++) {
            Message message = sendingMessageList.get(i);
            if (TextUtils.equals(message.getId(), messageId)) {
                messageBack = sendingMessageList.remove(i);
                break;
            }
        }
        Log.d(TAG, "removeInSendMessageList: 从消息发送集合移除的消息id :" + messageId + ",  消息发送集合长度是：" + sendingMessageList.size());
        return messageBack;
    }


    public void removeConversationListener() {
        conversationListener = null;
        for (Conversation conversation : conversationList) {
            conversation.removeConversationListener();
        }
    }


    public List<Conversation> getConversationList() {
        return conversationList;
    }


    @Override
    public void onConversationAdd(Conversation conversation) {
        if (!conversationList.contains(conversation)) {
            conversationList.add(conversation);
            if (conversationListener != null) {
                conversationListener.onConversationAdd(conversation);
            }
        }
    }

    @Override
    public void onConversationRemove(Conversation conversation) {
        conversationList.remove(conversation);
        //把会话作为临时会话，临时会话的作用是，不显示到会话列表页面，但是如果会话页面还是打开状态，在会话页面也能收到消息
        tempConversation = conversation;
        conversation.setTempConversation(true);
        conversation.deleteData();
        if (conversationListener != null) {
            conversationListener.onConversationRemove(conversation);
        }
    }

    @Override
    public void onConversationChange(Conversation conversation) {
        if (conversationListener != null) {
            conversationListener.onConversationChange(conversation);
        }
    }

    @Override
    public void onMessageChange(Conversation conversation) {
        if (conversationListener != null) {
            conversationListener.onMessageChange(conversation);
        }
    }

    @Override
    public void onUserInfoChange(Conversation conversation) {
        if (conversationListener != null) {
            conversationListener.onUserInfoChange(conversation);
        }
    }
}
